In [70]:
import random
import numpy
from random import randint
from IPython.html import widgets 
from IPython.display import display
from ipythonblocks import BlockGrid
from IPython.display import clear_output
from IPython.html.widgets import interact, interactive

The Schelling Model

Concept: The Grid Maker


In [106]:
#THE GRID MAKER WOOO!!!

grid_size = 5 #testing this grid maker

grid = BlockGrid(grid_size,grid_size)
for i in range(grid.height):
    for j in range(grid.width):
        rand_int1 = random.randint(1,3)
        if rand_int1 == 1:
            grid[i,j] = (0, 0, 255)
        elif rand_int1 == 2:
            grid[i,j] = (255, 0, 0)
        elif rand_int1 == 3:
            grid[i,j] = (0, 0, 0)
        
        if grid[i,j] == (0, 0, 255):
            grid[i,j] = blue_cell
        elif grid[i,j] == (255, 0, 0):
            grid[i,j] = red_cell
        elif grid[i,j] == (0, 0, 0):
            grid[i,j] = empty_cell
        cell1 = grid[i,j]
grid.show()


My First Attempt

This was really clever and cool but by reducing checking the neighbors to less than ten lines made it much harder to keep track of the satisfied and unsatisfied. It also made it difficult to move since my data had to be in a data frame for it to work. Here is my first attempt at it.


In [ ]:
#def move(population,satisfaction_thresh):
#    
#    not_satisfied_population = pd.DataFrame(population)
#    
#    for agent_coord in population:
#        
#        block = Schelling[tuple(agent_coord)]

#        coords_to_check = np.array([np.array(agent_coord) + np.array((1,0)),np.array(agent_coord) + np.array((1,1)), np.array(agent_coord) + np.array((0,1)),
#                           np.array(agent_coord) + np.array((1,-1)), np.array(agent_coord) + np.array((0,-1)),
#                           np.array(agent_coord) + np.array((-1,-1)), np.array(agent_coord) + np.array((-1,0)),
#                           np.array(agent_coord) + np.array((-1,1))])
#
#        coords_to_check = pd.DataFrame(coords_to_check)
#        coords_to_check = coords_to_check[coords_to_check>=0].dropna()
#        coords_to_check = coords_to_check[coords_to_check.ix[:,0] <= xsize-1].dropna()
#        coords_to_check = coords_to_check[coords_to_check.ix[:,1] <= ysize-1].dropna()
#        
#        if agent_coord == [2,4]:
#            display(coords_to_check)
#        number_of_neighbors = 0
#        same_neighbors = 0
#        dif_neighbors = 0
#        grey = (236,240,241)
#        
#        for check_coord in coords_to_check.values:##

#            check_block = Schelling[int(check_coord[0]),int(check_coord[1])]
#            
#            if check_block.rgb == block.rgb:
##                same_neighbors += 1
##                number_of_neighbors += 1
##                
##            if check_block.rgb != block.rgb and check_block.rgb != grey:
##                dif_neighbors += 1
##                number_of_neighbors += 1
##        
##        if number_of_neighbors == 0 or (same_neighbors-dif_neighbors)/number_of_neighbors >= satisfaction_thresh:
#             print('Satisfied!')
#             print(agent_coord)
#             print((same_neighbors-dif_neighbors)/number_of_neighbors)
#             print('\n')
            
#            not_satisfied_population = not_satisfied_population[not_satisfied_population.values != agent_coord]
#            not_satisfied_population.drop_duplicates(inplace = True)
    
#         else:
#             print('Not Satisfied!')
#             print(agent_coord)
#             print((same_neighbors-dif_neighbors)/number_of_neighbors)
#             print('\n')
    
#    return not_satisfied_population

Second Attempt

After talking to others and just discussing with others what they did, I decided to do a bunch of if statements instead of my previous attempt. This had advantages because it was easier to read, required no data frame to work, and was quite simple to execute.


In [61]:
#This checks the rgb of each cell; returns true if they are the same color.
def equal_rgb(a,b):
    if (a.red,a.green,a.blue)==(b.red,b.green,b.blue):
        return True 
    else:
        return False

In [62]:
#Checks if the rgb is black.
def equal_black(a):
    if (a.red == 0) and (a.green == 0) and (a.blue == 0):
        return True
    else:
        return False

Checking for Satisfaction AKA The Longest Function Ever


In [104]:
def satisfaction(grid,i,j):
    if grid[i,j]!=(0,0,0):      #if you are equal to black you will not enter the if statement
        GridSize = grid.width
        sat = 0                  #Count for saturation always will start at 0
                                 #Saturation meaning if the color is the same.
            
        if i == 0 or j == 0 or i == GridSize-1 or j == GridSize-1:   #Edges: have 5 possible neighbors
                
            MaxNeighbors = 5
#----------------------------The Corner Pieces------------
#----------------------------Upper Left Corner-------------                                                    
            if i == 0 and j == 0:   
                MaxNeighbors = 3    #The max neighbors is three in all corners

                                                      
                if equal_rgb(grid[i+1,j],grid[i,j]):    # Checking the neighbors
                    sat = sat + 1                       # If the color is equal, the 'True' will translate to an addition of 1 to sat
                elif equal_black(grid[i+1,j]):          # If the block is black, then the max neighbors goes down since no one is there. 
                    MaxNeighbors -= 1                   
                    
                if equal_rgb(grid[i+1,j+1],grid[i,j]): #same thing
                    sat = sat + 1 
                elif equal_black(grid[i+1,j+1]):         
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i,j+1],grid[i,j]):   #same thing
                    sat = sat + 1
                elif equal_black(grid[i,j+1]):
                    MaxNeighbors -= 1
                
                if MaxNeighbors == 0:   # No neighbors? Then you're not satisfied. 
                    satisfaction = 0    # Cannot divide by zero, so we can make satisfaction rating automatically 0.
                    return satisfaction
                else:
                    satisfaction = float(sat) / float(MaxNeighbors) #Had to make the satisfaction rating a float otherwise it would not work.
                    return satisfaction    
#-----------------------------Bottom Left Corner---------------------------------------
            elif i == 0 and j == GridSize-1:      

                MaxNeighbors = 3

                if equal_rgb(grid[i,j-1],grid[i,j]): 
                    sat = sat + 1
                elif equal_black(grid[i,j-1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i+1,j-1],grid[i,j]): 
                    sat = sat + 1
                elif equal_black(grid[i+1,j-1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i,j-1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i,j-1]):
                    MaxNeighbors -= 1
                
                if MaxNeighbors == 0:
                    satisfaction = 0
                    return satisfaction
                else:
                    satisfaction = float(sat) / float(MaxNeighbors)
                    return satisfaction

#---------------------------Upper Right Corner---------------------------------
            elif (i==GridSize-1 and j ==0):     

                MaxNeighbors = 3

                if equal_rgb(grid[i-1,j],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1,j]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i-1,j+1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1,j+1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i,j+1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i,j+1]):
                    MaxNeighbors -= 1
                
                if MaxNeighbors == 0:
                    satisfaction = 0
                    return satisfaction
                else:
                    satisfaction = float(sat) / float(MaxNeighbors)
                    return satisfaction
#------------------Bottom Right Corner---------------------------------------
            elif (i == GridSize-1  and j ==GridSize-1):  

                MaxNeighbors = 3

                if equal_rgb(grid[i-1,j],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1,j]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i-1,j-1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1,j-1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i,j-1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i,j-1]):
                    MaxNeighbors -= 1

                if MaxNeighbors == 0:
                    satisfaction = 0
                    return satisfaction
                else:
                    satisfaction = float(sat) / float(MaxNeighbors)
                    return satisfaction
#------------Edge Pieces-------------------------------------------
#------------The Left Edge-----------------------------------------
            elif i == 0 and j != 0 and j!=GridSize-1 :  
                if equal_rgb(grid[i+1,j],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i+1,j]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i+1,j+1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i+1,j+1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i+1,j-1],grid[i,j]): 
                    sat = sat + 1
                elif equal_black(grid[i+1,j-1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i,j-1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i,j-1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i,j+1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i,j+1]):
                    MaxNeighbors -= 1

                if MaxNeighbors == 0:
                    satisfaction = 0
                    return satisfaction
                else:
                    satisfaction = float(sat) / float(MaxNeighbors)
                    return satisfaction
#---------------------------The Top Edge------------------------------------------
            elif j == 0 and i!=0 and i!=GridSize-1: 
                if equal_rgb(grid[i+1,j],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i+1,j]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i+1,j+1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i+1,j+1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i,j+1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i,j+1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i-1,j+1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1,j+1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i-1,j],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1,j]):
                    MaxNeighbors -= 1
                
                if MaxNeighbors == 0:
                    satisfaction = 0
                    return satisfaction
                else:
                    satisfaction = float(sat) / float(MaxNeighbors)
                    return satisfaction
#-----------------------------------The Right Edge---------------------------------------------------
            elif i == GridSize-1 and j !=0 and j!=GridSize-1: 
                if equal_rgb(grid[i,j+1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i,j+1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i-1, j-1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1, j-1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i-1,j],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1,j]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i,j-1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i,j-1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i-1,j+1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1,j+1]):
                    MaxNeighbors -= 1
                
                if MaxNeighbors == 0:
                    satisfaction = 0
                    return satisfaction
                else:
                    satisfaction = float(sat) / float(MaxNeighbors)
                    return satisfaction
#--------------------------------------The Bottom Edge-----------------------------------
            elif j == GridSize-1 and i!=0 and i != GridSize-1: 
                if equal_rgb(grid[i+1,j],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i+1,j]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i-1, j-1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1, j-1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i-1,j],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i-1,j]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i,j-1],grid[i,j]):
                    sat = sat + 1
                elif equal_black(grid[i,j-1]):
                    MaxNeighbors -= 1
                    
                if equal_rgb(grid[i+1,j-1],grid[i,j]): 
                    sat = sat + 1
                elif equal_black(grid[i+1,j-1]):
                    MaxNeighbors -= 1
                
                if MaxNeighbors == 0:
                    satisfaction = 0
                    return satisfaction
                else:
                    satisfaction = float(sat) / float(MaxNeighbors)
                    return satisfaction

#-----------Cells not on the edge in the else statement. Must check all sides (8 neighbors max)-------------
        else:
            MaxNeighbors = 8
            if equal_rgb(grid[i+1,j],grid[i,j]):
                sat = sat + 1
            elif equal_black(grid[i+1,j],):
                MaxNeighbors -= 1
                
            if equal_rgb(grid[i+1,j+1],grid[i,j]):
                sat = sat + 1
            elif equal_black(grid[i+1,j+1]):
                MaxNeighbors -= 1
            
            if equal_rgb(grid[i,j+1],grid[i,j]):
                sat = sat + 1
            elif equal_black(grid[i,j+1]):
                MaxNeighbors -= 1
            
            if equal_rgb(grid[i-1, j-1],grid[i,j]):
                sat = sat + 1
            elif equal_black(grid[i-1, j-1]):
                MaxNeighbors -= 1
            
            if equal_rgb(grid[i-1,j],grid[i,j]):
                sat = sat + 1
            elif equal_black(grid[i-1,j]):
                MaxNeighbors -= 1
            
            if equal_rgb(grid[i,j-1],grid[i,j]):
                sat = sat + 1
            elif equal_black(grid[i,j-1]):
                MaxNeighbors -= 1
            
            if equal_rgb(grid[i-1,j+1],grid[i,j]):
                sat = sat + 1
            elif equal_black(grid[i-1,j+1]):
                MaxNeighbors -= 1
            
            if equal_rgb(grid[i+1,j-1],grid[i,j]): 
                sat = sat + 1
            elif equal_black(grid[i+1,j-1]):
                MaxNeighbors -= 1
            
            if MaxNeighbors == 0:
                satisfaction = 0
                return satisfaction
            else:
                satisfaction = float(sat) / float(MaxNeighbors)
                return satisfaction

    else:            #If it's black then nothing happens
        return None

In [ ]:
def find_movers(grid,threshold):            
    movers = []
    nulls = []
    for i in range(grid.width):             #Iterates through the grid.
        for j in range(grid.height):
            if equal_black(grid[i,j]):      #Finds empty cells
                nulls.append((i,j))         #These cells are appended (something I could not do with my first attempt at this!)
            else:                           #Else means colored cells
                if satisfaction(grid,i,j) < threshold:  #compares satisfaction to the satisfaction threshold, aka the percent a cell desires for similar race neighbors
                    movers.append((i,j))                #The cells that are not satisfied are appended to movers     
    
    
    for i in range(len(movers)-1):             #Loops through movers list
        if len(nulls) != 0:                    # Needs this to fix error if the length is 0
            p = random.randint(0,len(nulls)-1) # picks random indice from nulls aka our black cells.
            
            
            
#This next part changes the color of the black cells to the mover cell. The movers then turn into black cells.
#nulls are removed since they are no longer nulls until the next iteration.
            grid[nulls[p]].rgb = grid[movers[i]].rgb 
            grid[movers[i]].rgb = (0,0,0)   
            nulls.remove(nulls[p])          
       
    clear_output() #We can see changes with the block grid with clear_output()           
    grid.show()

In [108]:
#THIS IS THE THING!!

def Schelling(Grid_Size=100,Threshold=0.5,RedPop=60,BluePop=30,Iterations=1):    # How this part should look once we're using the sliders
    grid = BlockGrid(Grid_Size,Grid_Size)           #Creates grid

    if (RedPop + BluePop)> 100:                    #Makes sure the total population does not exceed 100%
        print ("Values of (red plus blue) must not exceed 100 %")
    else:
        for i in range(grid.height):                 #This is basically the random generator from before.
            for j in range(grid.width):              #The percent of it happening depends on the percent from the sliders
                rand_int1 = random.randint(1,100)    
                if rand_int1 <= BluePop:             
                    grid[i,j] = (0, 0, 255)          
                elif rand_int1 <= (RedPop + BluePop):
                    grid[i,j] = (255, 0, 0)          
                elif rand_int1 > (RedPop + BluePop): 
                    grid[i,j] = (0, 0, 0)            
        grid.show()                                    
                                                
                                                        
    while Iterations > 0:            #Running iterations as long as there are unsatisfied cells.
        find_movers(grid,Threshold)  #Finds the movers
        Iterations = Iterations - 1  #While loops can be stopped with this code :) 
x = interact(Schelling,GridSize=(5,100,1), Threshold=(0,1,.05), RedPop = (0,100,5), BluePop = (0,100,5) , Iterations = (0,400,5))#CODE FOR SLIDERS



In [96]:
numpy.savez(Schelling(Grid_Size=50,Threshold=0.5,RedPop=80,BluePop=10,Iterations=150))



In [102]:
numpy.savez(Schelling(Grid_Size=50,Threshold=0.5,RedPop=40,BluePop=40,Iterations=150))



In [98]:
def SchellingQ1(Grid_Size=50,Threshold=0.5,RedPop=50,BluePop=30, PurplePop = 10, GreenPop = 5,Iterations=1):
    # How this part should look once we're using the sliders

    grid = BlockGrid(Grid_Size,Grid_Size)           #Creates grid

    if (RedPop + BluePop + GreenPop + PurplePop)> 100:                    
        SchellingQ1(Grid_Size=50,Threshold=0.5,RedPop=50,BluePop=30, PurplePop = 10, GreenPop = 5,Iterations=1)
        print ("Values of (red plus blue plus purple plus green) must not exceed 100 %")
    else:
        for i in range(grid.height):                 
            for j in range(grid.width):              
                rand_int1 = random.randint(1,100)    
                if rand_int1 <= BluePop:             
                    grid[i,j] = (0, 0, 255)          
                elif rand_int1 <= (RedPop + BluePop): 
                    grid[i,j] = (255, 0, 0)         
                elif rand_int1 <= (RedPop + BluePop + GreenPop):
                    grid[i,j] = (0, 255, 0)
                elif rand_int1 <= (RedPop + BluePop + GreenPop + PurplePop):
                    grid[i,j] = (255, 0, 255)
                elif rand_int1 > (RedPop + BluePop + GreenPop + PurplePop):
                    grid[i,j] = (0, 0, 0)            
        grid.show()                                   
                                                        
    while Iterations > 0:            
        find_movers(grid,Threshold)  
        Iterations = Iterations - 1 
x = interact(SchellingQ1,GridSize=(5,100,5), Threshold=(0,1,.05), RedPop = (0,100,5), BluePop = (0,100,5) , GreenPop = (0,100,5), PurplePop = (0,100,5), Iterations = (0,400,5))



In [75]:
numpy.savez(file = SchellingQ1(Grid_Size=50,Threshold=0.5,RedPop=50,BluePop=30, PurplePop = 10, GreenPop = 5,Iterations=35))



In [84]:
numpy.savez(file = SchellingQ1(Grid_Size=50,Threshold=0.5,RedPop=50,BluePop=30, PurplePop = 10, GreenPop = 5,Iterations=100))



In [85]:
numpy.savez(file = SchellingQ1(Grid_Size=50,Threshold=0.5,RedPop=50,BluePop=30, PurplePop = 10, GreenPop = 5,Iterations=200))


Actual Data: The Racial Dot Map

This is actual data taken from the 2010 Census. These pictures were taken from The Cooper Center, using SAS and Python to create the maps/pictures. Here is the link to the website:

http://www.coopercenter.org/demographics/Racial-Dot-Map

I chose Indianapolis, San Luis Obispo, and San Francisco as places of interest. As you can see, each city already shows different races or colors clumping together. I am using this as a part of my presentation to answer the question: Can our use of Python predict how neighborhoods will be created in real life?

Indianapolis

Indianapolis is the perfect example of two races being represented and how their communities form. Very similar to code using two races, with a fairly even percentage of races being represented.

San Luis Obispo

This is San Luis Obispo. San luis Obispo is the perfect example of one race dominating over others. The minority will be grouped sporadically in the map (both in the Python code and real life)

San Francisco: Where Schelling Kind of Fails

Looking at San Franciso, Schelling comes close, but it is clear that the saturation of colors is pretty mixed in the middle of San Francisco. In my Python model for Schelling for more than one race, it shows the clumping of similar ethnicities. In the real world, at least in the United States in densely populated cities where multiple races are found, other variables come into play aside from race preference (e.g. socioeconomic status, schools, highway access, etc.).

The End!